/*******************************************************************
This file is part of iAgenda.

iAgenda is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

iAgenda is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with iAgenda.  If not, see <http://www.gnu.org/licenses/>.
*******************************************************************/

#include "stdafx.h"
#include "ListDataPoom2.h"
#include "FileUtils.h"

IPOutlookApp2 *             polApp2;
IFolder *                   pCurrFldr2;
IPOutlookItemCollection *   pItemCol2;
const TCHAR *               tszCategory2;
//UINT                        nBitmapHeight;
//UINT                        nBitmapWidth;


// Internal functions to be used by the functions in this file
HRESULT initPoom2(ScreenDefinition hgScreen);

// http://msdn.microsoft.com/en-us/library/bb446087.aspx
HRESULT Poom2CategoriesPopulate( ScreenDefinition  hgScreen,DataItem * parent, void (*adder)(DataItem*),
                     CSettings * pSettings) {

    HRESULT           hr = E_FAIL;
    IFolder    * pFolder = NULL;
    IItem * pFolderIItem = NULL;
    CEPROPVAL    * pVals = NULL;
    ULONG       cbBuffer = 0;
    int            index = 0;
    DataItem        data = {0};

    data.ID = 1;
    data.iGroup = 0;
    data.isFavorite = false;
    data.isOverdue = false;
    data.oId = 0;
    data.type = diListItem;

    data.ID = 0;
    StringCchCopy(data.szPrimaryText, 64, pSettings->alltasks_string); 
    adder(&data);

    data.ID = 1;

    CEPROPID rgPropID = PIMPR_FOLDER_CATEGORIES;

	initPoom2(hgScreen); //hg added hgScreen
    HANDLE hHeap = GetProcessHeap();

    // Get the IFolder object (Contacts, Calendar, Tasks).
    hr = polApp2->GetDefaultFolder(olFolderTasks, &pFolder); 
    CHR(hr);

    // Get the IItem object representing a IFolder object.
    hr = pFolder->QueryInterface(__uuidof(IItem), (LPVOID*)&pFolderIItem);
    CHR(hr);

    // Get the list of categories.
    hr = pFolderIItem->GetProps(&rgPropID, CEDB_ALLOWREALLOC, 1, &pVals, &cbBuffer, hHeap);
    CHR(hr);

    // Copy the list of categories for use outside of this function.
    TCHAR * start = pVals->val.lpwstr;
    TCHAR * end = start + _tcslen(pVals->val.lpwstr);
    TCHAR * comma;
    while (start < end) {
        comma = _tcschr(start, ',');
        if (comma == NULL) comma = end;
        hr = StringCchCopyN(data.szPrimaryText, 64, start, comma - start);
        data.isFavorite = 0 == _tcscmp(data.szPrimaryText, pSettings->favorite_category);
        CHR(hr);
        adder(&data);
        start = comma + 2;
    }

Error:
    // Free resources.
    HeapFree(hHeap, 0, pVals);
    RELEASE_OBJ(pFolderIItem);
    RELEASE_OBJ(pFolder);

    return index;
}

HRESULT Poom2CategoriesGetTitle(ScreenDefinition hgScreen,DataItem * parent, TCHAR * buffer, int cchDest,
                               CSettings * pSettings) {

    StringCchCopy(buffer, cchDest, pSettings->categories_string);
    return S_OK;
}

HRESULT Poom2CategoriesClick(ScreenDefinition hgScreen,DataItem * data, float x, 
                            int * newScreen, CSettings * pSettings) {
    
    if (_tcsstr(data->szPrimaryText, pSettings->alltasks_string))
        *newScreen = 2;
    else if (_tcsstr(data->szPrimaryText, pSettings->favorite_category))
        *newScreen = 0;
    else
        *newScreen = 6;
    return S_OK;
}

// *************************************************
// These functions are for the main list of appointments
// *************************************************

HRESULT Poom2Populate( ScreenDefinition hgScreen,DataItem * parent, void (*adder)(DataItem*),
                     CSettings * pSettings) {

    HRESULT hr = S_OK;
    BSTR bstrPrimary = NULL;
    BSTR bstrCategories = NULL;
    DWORD dwNumberOfBytesWritten = 0;
    TCHAR buffer[PRIMARY_TEXT_LENGTH];

    // This will hold our "next" list item, which we'll later
    // pass to this->_addListItem
    DataItem data = {0};
    data.iGroup = 0;
    data.isFavorite = false;
    data.isOverdue = false;
	data.isUndated = false;
    data.type = diListItem;

	hr = initPoom2(hgScreen);//hg added hgScreen
    CHR(hr);

    // Get the appointments folder.
    hr = polApp2->GetDefaultFolder(olFolderTasks, &pCurrFldr2);  
    CHR(hr);

    // Get the appointments Items collection.
    hr = pCurrFldr2->get_Items(&pItemCol2);
    CHR(hr);

    // parent's ID == 0 means: use all appointments
    // parent's ID == 1 means: restrict dataset to parent's primary text
    if (1 == parent->ID) {
        StringCchPrintf(buffer, PRIMARY_TEXT_LENGTH, 
            TEXT("[Categories] = \"%s\""), parent->szPrimaryText);
        hr = pItemCol2->Restrict((BSTR)buffer, &pItemCol2);
        CHR(hr);
    }

	// now apply other restrictions here
	hr = pItemCol2->Restrict(TEXT("[Complete] = false"), &pItemCol2);
	CHR(hr);

	/*add here:
	StringCchCopy(options[index++], MAX_LOADSTRING, TEXT("Category"));
	StringCchCopy(options[index++], MAX_LOADSTRING, TEXT("Due Date"));
	StringCchCopy(options[index++], MAX_LOADSTRING, TEXT("Priority"));
	StringCchCopy(options[index++], MAX_LOADSTRING, TEXT("Don't Sort"));

	code for sorting */

	
	TCHAR mytimespan[32];// = pSettings->period_filter;
	//StringCchCopy(mytimespan, 32, pSettings->period_filter);
	//int myinttimespan;

	//if(CompareString(LOCALE_NEUTRAL, NORM_IGNORECASE, pSettings->sort_tasks, -1, TEXT("Category"), -1) == CSTR_EQUAL)
	//	StringCchCopy(mytimespan, 32, TEXT("[Category]"));
	if(CompareString(LOCALE_NEUTRAL, NORM_IGNORECASE, pSettings->sort_tasks, -1, TEXT("Due Date"), -1) == CSTR_EQUAL)
		StringCchCopy(mytimespan, 32, TEXT("[DueDate]"));
	else if(CompareString(LOCALE_NEUTRAL, NORM_IGNORECASE, pSettings->sort_tasks, -1, TEXT("Priority"), -1) == CSTR_EQUAL)
		StringCchCopy(mytimespan, 32, TEXT("[Priority]"));
	else if(CompareString(LOCALE_NEUTRAL, NORM_IGNORECASE, pSettings->sort_tasks, -1, TEXT("Don't Sort"), -1) == CSTR_EQUAL)
		StringCchCopy(mytimespan, 32, TEXT("[]"));


	// sort by duedate - taken from hgl - NOT TESTED YET
//	hr = pItemCol2->Sort(TEXT("[DueDate]"), VARIANT_TRUE);  
	 hr = pItemCol2->Sort(mytimespan, VARIANT_TRUE);//hg 4/2/09
	//hr = pItemCol2->Sort(mytimespan, VARIANT_FALSE);  //hg sorts overdue first
		//=> however, all but one task is shown as overdue,
	CHR(hr);



	ITask * pTask = NULL;

    int cItems;
	pItemCol2->get_Count(&cItems);

	for (int i = 0; i < cItems; i++) {

        // the itemCollection is indexed 1-based, weird...
        hr = pItemCol2->Item(i+1, (IDispatch**)&pTask);
        if (FAILED(hr))
            continue;

	    // grab properties
	    hr = pTask->get_Oid(&data.oId);
        CHR(hr);

        hr = pTask->get_Subject(&bstrPrimary); 
        CHR(hr);
        StringCchCopy(data.szPrimaryText, PRIMARY_TEXT_LENGTH, bstrPrimary);
        SysFreeString(bstrPrimary);

        // Determine if this is a favorite 
        hr = pTask->get_Categories(&bstrCategories); 
        CHR(hr);
        data.isFavorite = NULL != 
            _tcsstr(bstrCategories, pSettings->favorite_category);
        SysFreeString(bstrCategories);

	    // Don't display groups if filtered by category
        if (NULL == tszCategory2) {
		    data.iGroup = (int)_totupper(data.szPrimaryText[0]);
        }

		//group by date (seems to work except undated)
		DATE bufferTime;
		UINT myInt;

		pTask->get_DueDate(&bufferTime);
		myInt = _getPastTime(_poomDateToLocal(bufferTime));

		SYSTEMTIME stToday;
		GetLocalTime(&stToday);
		UINT uToday = _getDaySerial(&stToday);

		// this is the date to be checked for undated tasks!
		SYSTEMTIME stDate;
		VariantTimeToSystemTime(bufferTime, &stDate);


		if(stDate.wYear == 4501) // undated task?
		{
			//MessageBox(NULL,TEXT("undated"),TEXT(""),MB_OK);
			data.isUndated = TRUE;
		}
		else
			data.isUndated = false;

		if (myInt < uToday)
			data.isOverdue = TRUE;


		//now we know if it's overdue, grouping
		if(data.isUndated)
			data.iGroup = 99;
		else if(data.isOverdue)
			data.iGroup = 100; // todo: check if this must remain hardcoded
		else
		{
			pTask->get_StartDate(&bufferTime);
			data.iGroup = _getPastTime(_poomDateToLocal(bufferTime), data.szSecondaryText, 
				SECONDARY_TEXT_LENGTH);

			StringCchCopy(data.szTertiaryText, SECONDARY_TEXT_LENGTH, TEXT(""));
		}

        adder(&data); 

		// clean up
        RELEASE_OBJ(pTask);
    }

    hr = S_OK;

Error:
    SysFreeString(bstrPrimary);
    SysFreeString(bstrCategories);
	RELEASE_OBJ(pTask);  
    return hr;
}

HRESULT Poom2Click(ScreenDefinition hgScreen,DataItem * data, float x,  
                  int * newScreen, CSettings * pSettings) {
    *newScreen = 5;
    return S_OK;
}

HRESULT Poom2GetTitle(ScreenDefinition hgScreen,DataItem * parent, TCHAR * buffer, int cchDest,
                               CSettings * pSettings) {

    StringCchCopy(buffer, cchDest, parent->szPrimaryText);
    return S_OK;
}

HRESULT Poom2GetGroup(ScreenDefinition hgScreen,DataItem * data, TCHAR * buffer, int cchDest,
                     CSettings * pSettings) {

	UINT g = data->iGroup;
	
	SYSTEMTIME stToday;
	GetLocalTime(&stToday);
	UINT uToday = _getDaySerial(&stToday);

	if(data->isUndated)
		StringCchCopy(buffer, cchDest, TEXT("Undated tasks")); //TODO: change this to settings->undated_string
	else if(data->isOverdue)
		StringCchCopy(buffer, cchDest, pSettings->overdue_string);
	else if (g - uToday == 0) {
		StringCchCopy(buffer, cchDest, pSettings->today_string);
	}
	else if (g - uToday == 1) {
		StringCchCopy(buffer, cchDest, pSettings->tomorrow_string);
	}
	else if (g - uToday <= 7 /*&& g - uToday > 1*/) {
		g = g % 7;
		StringCchCopy(buffer, cchDest, 
			g == 0 ? pSettings->sunday_string
			: g == 1 ? pSettings->monday_string
			: g == 2 ? pSettings->tuesday_string
			: g == 3 ? pSettings->wednesday_string
			: g == 4 ? pSettings->thursday_string
			: g == 5 ? pSettings->friday_string
			: pSettings->saturday_string
			);
	}
	else {
		SYSTEMTIME st;
		_fillSystemTimeFromSerial(&st, g);
		GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st,
			NULL, buffer, cchDest);
	}

	return S_OK;
}

HRESULT Poom2AddItem(ScreenDefinition hgScreen) {
    IDispatch * pDisp = NULL;
    IItem * pItem = NULL;
    HRESULT hr = S_OK;
    HWND hWnd;

	hr = initPoom2(hgScreen); //hg added hgScreen
    CHR(hr);

    hr = polApp2->CreateItem(olTaskItem, (IDispatch**)&pDisp);
    CHR(hr);

    hr = pDisp->QueryInterface(IID_IItem, (LPVOID*)&pItem);
    CHR(hr);

    hWnd = FindWindow (SZ_APP_NAME, NULL);
	hr = pItem->Edit(hWnd);

Error:
	RELEASE_OBJ(pItem);
    RELEASE_OBJ(pDisp);
    return hr;
}

// *************************************************
// These functions are for the favorites list of appointments
// *************************************************


// *************************************************
// These functions are for an appointment details screen
// *************************************************

HRESULT Poom2DetailsPopulate(ScreenDefinition  hgScreen, DataItem * parent, void (*adder)(DataItem*),
                            CSettings * pSettings) {
    HRESULT hr = S_OK;
	ITask * pTask = NULL;

    BSTR buffer = NULL;
    BSTR bstrCategories = NULL;
    int id = parent->ID;
    TCHAR * szName = parent->szPrimaryText;
    DWORD dwNumberOfBytesWritten = 0;
	//allelimo
	DATE bufferTime;
	LONG iImportance = 0;
	TCHAR strImportance[PRIMARY_TEXT_LENGTH] = {NULL};

    // Initialize the data item that we're going to write
    DataItem data = {0};
    data.ID = 0;
    data.iGroup = 0;
    data.isFavorite = false;
    data.isOverdue = false;
    data.oId = parent->oId;

	hr = initPoom2(hgScreen);//hg added hgScreen
    CHR(hr);

    // GET CURRENT APPOINTMENT
    hr = polApp2->GetItemFromOid((CEOID)data.oId, (IDispatch**)&pTask);
    CHR(hr);

    //***** GET APPOINTMENT DETAILS *****
 
	// Subject 
	pTask->get_Subject(&buffer);
	StringCchCopy(data.szPrimaryText, PRIMARY_TEXT_LENGTH, buffer);
	SysFreeString(buffer);
	data.type = diName;
	adder(&data); 

	//allelimo - importance
	pTask->get_Importance(&iImportance);

	switch (iImportance)
	{
	case olImportanceLow:
		StringCchCopy(strImportance, PRIMARY_TEXT_LENGTH, pSettings->priority_string);  //TEXT("Priority: Low")
		StringCchCat(strImportance, PRIMARY_TEXT_LENGTH, TEXT(": "));
		StringCchCat(strImportance, PRIMARY_TEXT_LENGTH, pSettings->low_string);
		break;
	case olImportanceHigh:
		StringCchCopy(strImportance, PRIMARY_TEXT_LENGTH, pSettings->priority_string);  //TEXT("Priority: Low")
		StringCchCat(strImportance, PRIMARY_TEXT_LENGTH, TEXT(": "));
		StringCchCat(strImportance, PRIMARY_TEXT_LENGTH, pSettings->high_string);
	default:
		StringCchCopy(strImportance, PRIMARY_TEXT_LENGTH, pSettings->priority_string);  //TEXT("Priority: Low")
		StringCchCat(strImportance, PRIMARY_TEXT_LENGTH, TEXT(": "));
		StringCchCat(strImportance, PRIMARY_TEXT_LENGTH, pSettings->normal_string);
	}
	
	StringCchCopy(data.szPrimaryText, PRIMARY_TEXT_LENGTH, strImportance);
	//SysFreeString(strImportance);
	data.type = diName2;
	adder(&data);

	// due date
	pTask->get_DueDate(&bufferTime);
	_printPoomDate2(data.szPrimaryText, PRIMARY_TEXT_LENGTH, 
		_poomDateToLocal(bufferTime));

	StringCchCopy(data.szSecondaryText, SECONDARY_TEXT_LENGTH, pSettings->duedate_string);

	data.type = diDateTime; 
	adder(&data);

	// Category
	pTask->get_Categories(&buffer);
	StringCchCopy(data.szPrimaryText, PRIMARY_TEXT_LENGTH, buffer);
	SysFreeString(buffer);
	data.type = diCategory;
	adder(&data); 

    // Button to show details
    data.type = diDetailsButton;
    StringCchCopy(data.szPrimaryText, PRIMARY_TEXT_LENGTH, pSettings->managetask_string);
    SysFreeString(buffer);
    adder(&data); 

    // Button to edit appointment
    data.type = diEditButton;
    StringCchCopy(data.szPrimaryText, PRIMARY_TEXT_LENGTH, pSettings->edittask_string);
    SysFreeString(buffer);
    adder(&data); 

    hr = S_OK;

Error:
    // cleanup
    if (NULL != bstrCategories)
        SysFreeString(bstrCategories);
    if (NULL != buffer)
        SysFreeString(buffer);
    RELEASE_OBJ(pTask); 

    return hr;
}

HRESULT Poom2DetailsGetTitle(ScreenDefinition hgScreen,DataItem * parent, TCHAR * buffer, int cchDest,
                               CSettings * pSettings) {

    StringCchCopy(buffer, cchDest, pSettings->details_string);
    return S_OK;
}

HRESULT Poom2DetailsClick(ScreenDefinition hgScreen,DataItem * data, float x, 
                         int * newScreen, CSettings * pSettings) {
    HRESULT hr = S_OK;
    IDispatch * pDisp = NULL;
    IItem * pItem = NULL;
 	ITask * pTask = NULL;
    BSTR buffer = NULL;
    HWND hWnd = 0;

    int oid = data->oId;
    if (oid == -1)
        return E_INVALIDARG;

	hr = initPoom2(hgScreen);//hg added hgScreen
    CHR(hr);

    hr = polApp2->GetItemFromOid(oid, &pDisp);
    CHR(hr);

    switch (data->type) {
        case diEditButton:
            hr = pDisp->QueryInterface(IID_IItem, (LPVOID*)&pItem);
            CHR(hr);
            hWnd = FindWindow (SZ_APP_NAME, NULL);
        	hr = pItem->Edit(hWnd);
            break;

        case diDetailsButton:
            hr = pDisp->QueryInterface(IID_IItem, (LPVOID*)&pItem);
            CHR(hr);
            hWnd = FindWindow (SZ_APP_NAME, NULL);
        	hr = pItem->Display(hWnd);
            CHR(hr);
            break;
    }

    hr = S_OK;

Error:
	RELEASE_OBJ(pItem);
	RELEASE_OBJ(pTask);
    RELEASE_OBJ(pDisp);
    return hr;
}

HRESULT Poom2DetailsToggleFavorite(ScreenDefinition hgScreen,DataItem * data, CSettings * pSettings) {
    IDispatch * pDisp = NULL;
    IItem * pItem = NULL;
    HRESULT hr = S_OK;

    int oid = data->oId;
    if (oid == -1)
        return E_INVALIDARG;

	hr = initPoom2(hgScreen);//hg added hgScreen
    CHR(hr);

    hr = polApp2->GetItemFromOid(oid, &pDisp);
    CHR(hr);

    hr = pDisp->QueryInterface(IID_IItem, (LPVOID*)&pItem);
    CHR(hr);

    // update the categories in the POOM
    hr = (data->isFavorite)
        ? pItem->RemoveCategory(pSettings->favorite_category)
        : pItem->AddCategory(pSettings->favorite_category);
    CHR(hr);

    // category update succeeded
    hr = pItem->Save();

    // update the list data
    data->isFavorite = !data->isFavorite;

Error:
    RELEASE_OBJ(pItem);
    RELEASE_OBJ(pDisp);

    return hr;
}


// *************************************************
// Internal functions to be used only by the functions in this file
// *************************************************

HRESULT initPoom2(ScreenDefinition hgScreen) {
	HWND      hWnd     = 0;
    HRESULT   hr       = 0;
    IFolder   *pFolder = NULL;
    IItem     *pItem   = NULL;
    CEPROPVAL propval  = {0};
	
    if (polApp2 == NULL) {
        hr = CoCreateInstance(__uuidof(Application), NULL, CLSCTX_INPROC_SERVER,
                              __uuidof(IPOutlookApp2), (LPVOID*) &polApp2);
        CHR(hr);
    
		hWnd = FindWindow (SZ_APP_NAME, NULL);
        hr = polApp2->Logon((long)hWnd);
        CHR(hr);
		
		// register for updates
		// http://msdn.microsoft.com/en-us/library/ms862902.aspx
    
	    // Get the folder for appointments.
	    hr = polApp2->GetDefaultFolder(olFolderTasks, &pFolder);
        CHR(hr);

	    // Get the IItem interface for the IFolder.
	    hr = pFolder->QueryInterface(IID_IItem, (LPVOID*)&pItem);
        CHR(hr);

	    // Set the folder's properties.
	    propval.propid    = PIMPR_FOLDERNOTIFICATIONS;
	    propval.val.ulVal = PIMFOLDERNOTIFICATION_ALL;
	    hr                = pItem->SetProps(0, 1, &propval);

        CHR(hr);
    }

    hr = S_OK;

Error:
	RELEASE_OBJ(pItem);
	RELEASE_OBJ(pFolder);
    if (FAILED(hr)) {
        // If we failed to log on, don't keep the object around
        RELEASE_OBJ(polApp2);
    }
    return hr;
}


